  * Applied some patches from OpenBSD:
    + Use mkstemp to create temporary files	
    + Kill -s now works
    + Escapes special characters in tab completitions
    + Introduce FSH flag, which is set when the shell is called as `sh'.
    + tree.c: Fix three off-by-one errors.
    + c_sh.c: don't set close-on-exec flag on file descriptors in FSH mode
      (closes: #154540). Documented the change in ksh(1).
    + history.c: Compare the return from mmap with MAP_FAILED, do not cast it
      to int and compare with -1.
    + main.c: set edit mode to emacs by default, may be overridden by the
      environment or the user.  Also, we want tab completion in vi by default.
    + misc.c: use strtol() in getn().
    + emacs.c:
       - bind TAB (^I) to complete-list by default
       - complete-list first completes; if that does not work, it lists
       - fix a memleak in do_complete()
    + edit.c:
       - completion now works after '=' (dd), and ':' (ssh) and ` (backtick)
       - add '#' to the list of escaped characters during vi/emacs filename
         completion

    + exec.c: Found and fixed yet another problem with `set -e' scripts
      (see a changelog entry for 5.2.14-3), which caused `dpkg-buildpackage -B'
      to fail on systems where /bin/sh is ksh.
  
    + c_sh.c: Make `set' command return 0 always, not only in the POSIX mode.
      According to Jeff Sheinberg <jeffsh@localnet.com>, this new behaviour
      is more compatible with SUSv2 standard and other shells (esp. ksh93)
      (closes: #118476). Documented the change in ksh(1) man page.

    + c_test.c: The special case code for "test -x" over NFS was
      incorrect.  The right thing to do is to try access(2) first
      (since that occurs on the NFS server side) and only check for the
      absence of an execute bit when access(2) succeeds.
    + edit.c: in word location, fix forward scanning so it correctly
      account for any escaped char and not only spaces.  for "foo
      (bar.a)" and "foo (bar a)", cd foo\ \(bar.<tab> will correctly
      expand to foo\ \(bar.a\).

    + vi.c: Buffers are not strings so use memcpy(), not strlcpy() to copy
      them. Also add some further bounds checks in the name of paranoia.
    + exec.c: Unbreak parameter assignment when calling bourne style
      functions.
    + exec.c: For the >& and <& operators, add a check for "dup from" ==
      "dup to" and just return success if they are the same.  Fixes the
      "ls 2>&2" problem.
    + eval.c, exec.c, io.c, jobs.c: If "from fd" == "to fd" don't call
      dup2() or close "from fd".
     
Index: pdksh-5.2.14/c_ksh.c
===================================================================
--- pdksh-5.2.14.orig/c_ksh.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/c_ksh.c	2009-09-17 00:32:08.000000000 +0200
@@ -1208,6 +1208,7 @@
 						builtin_opt.optarg);
 					return 1;
 				}
+				break;
 			  case '?':
 				return 1;
 			}
Index: pdksh-5.2.14/edit.c
===================================================================
--- pdksh-5.2.14.orig/edit.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/edit.c	2009-09-17 00:32:08.000000000 +0200
@@ -15,6 +15,9 @@
 # include <sys/stream.h>	/* needed for <sys/ptem.h> */
 # include <sys/ptem.h>		/* needed for struct winsize */
 #endif /* OS_SCO */
+#ifdef DEBIAN
+#include <sys/ioctl.h>
+#endif /* DEBIAN */
 #include <ctype.h>
 #include "ksh_stat.h"
 
@@ -552,7 +555,11 @@
 {
 	char *toglob;
 	char **words;
+#ifndef DEBIAN
 	int nwords;
+#else /* DEBIAN */ /* patch from OpenBSD */
+	int nwords, i, idx, escaping;
+#endif /* DEBIAN */
 	XPtrV w;
 	struct source *s, *sold;
 
@@ -561,6 +568,22 @@
 
 	toglob = add_glob(str, slen);
 
+#ifdef DEBIAN /* patch from OpenBSD */
+	/* remove all escaping backward slashes */
+	escaping = 0;
+	for(i = 0, idx = 0; toglob[i]; i++) {
+		if (toglob[i] == '\\' && !escaping) {
+			escaping = 1;
+			continue;
+		}
+
+		toglob[idx] = toglob[i];
+		idx++;
+		if (escaping) escaping = 0;
+	}
+	toglob[idx] = '\0';
+
+#endif /* DEBIAN */
 	/*
 	 * Convert "foo*" (toglob) to an array of strings (words)
 	 */
@@ -722,7 +745,12 @@
 	return nwords;
 }
 
+#ifndef DEBIAN
 #define IS_WORDC(c)	!(ctype(c, C_LEX1) || (c) == '\'' || (c) == '"')
+#else /* patch from OpenBSD */
+#define IS_WORDC(c)	!( ctype(c, C_LEX1) || (c) == '\'' || (c) == '"'  \
+			    || (c) == '`' || (c) == '=' || (c) == ':' )
+#endif
 
 static int
 x_locate_word(buf, buflen, pos, startp, is_commandp)
@@ -747,11 +775,23 @@
 	/* Keep going backwards to start of word (has effect of allowing
 	 * one blank after the end of a word)
 	 */
+#ifndef DEBIAN
 	for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
+#else /* DEBIAN */ /* patch from OpenBSD */
+	for (; (start > 0 && IS_WORDC(buf[start - 1]))
+		|| (start > 1 && buf[start-2] == '\\'); start--)
+#endif /* DEBIAN */
 		;
 	/* Go forwards to end of word */
+#ifndef DEBIAN
 	for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
 		;
+#else /* DEBIAN */ /* patch from OpenBSD */
+	for (end = start; end < buflen && IS_WORDC(buf[end]); end++) {
+		if (buf[end] == '\\' && (end+1) < buflen)
+			end++;
+	}
+#endif /* DEBIAN */
 
 	if (is_commandp) {
 		int iscmd;
@@ -759,7 +799,11 @@
 		/* Figure out if this is a command */
 		for (p = start - 1; p >= 0 && isspace(buf[p]); p--)
 			;
+#ifndef DEBIAN
 		iscmd = p < 0 || strchr(";|&()", buf[p]);
+#else /* DEBIAN */ /* patch from OpenBSD */
+		iscmd = p < 0 || strchr(";|&()`", buf[p]);
+#endif
 		if (iscmd) {
 			/* If command has a /, path, etc. is not searched;
 			 * only current directory is searched, which is just
@@ -961,6 +1005,9 @@
 {
 	const char *sp, *p;
 	char *xp;
+#ifdef DEBIAN /* patch from OpenBSD */
+	int staterr;
+#endif /* DEBIAN */
 	int pathlen;
 	int patlen;
 	int oldsize, newsize, i, j;
@@ -995,13 +1042,23 @@
 		memcpy(xp, pat, patlen);
 
 		oldsize = XPsize(*wp);
+#ifndef DEBIAN
 		glob_str(Xstring(xs, xp), wp, 0);
+#else /* DEBIAN */ /* patch from OpenBSD */
+		glob_str(Xstring(xs, xp), wp, 1); /* mark dirs */
+#endif
 		newsize = XPsize(*wp);
 
 		/* Check that each match is executable... */
 		words = (char **) XPptrv(*wp);
 		for (i = j = oldsize; i < newsize; i++) {
+#ifndef DEBIAN
 			if (search_access(words[i], X_OK, (int *) 0) >= 0) {
+#else /* DEBIAN */ /* patch from OpenBSD */
+			staterr = 0;
+			if ((search_access(words[i], X_OK, &staterr) >= 0)
+			    || (staterr == EISDIR)) {
+#endif
 				words[j] = words[i];
 				if (!(flags & XCF_FULLPATH))
 					memmove(words[j], words[j] + pathlen,
@@ -1018,4 +1075,42 @@
 	Xfree(xs, xp);
 }
 
+#ifdef DEBIAN /* patch from OpenBSD */
+/*
+ * if argument string contains any special characters, they will
+ * be escaped and the result will be put into edit buffer by
+ * keybinding-specific function
+ */
+int
+x_escape(s, len, putbuf_func)
+	const char *s;
+	size_t len;
+	int putbuf_func ARGS((const char *s, size_t len));
+{
+	size_t add, wlen;
+	const char *ifs = str_val(local("IFS", 0));
+	int rval=0;
+
+	for (add = 0, wlen = len; wlen - add > 0; add++) {
+		if (strchr("\\$(){}*&;#|<>\"'`", s[add]) || strchr(ifs, s[add])) {
+			if (putbuf_func(s, add) != 0) {
+				rval = -1;
+				break;
+			}
+
+			putbuf_func("\\", 1);
+			putbuf_func(&s[add], 1);
+
+			add++;
+			wlen -= add;
+			s += add;
+			add = -1; /* after the increment it will go to 0 */
+		}
+	}
+	if (wlen > 0 && rval == 0)
+		rval = putbuf_func(s, wlen);
+
+	return (rval);
+}
+#endif /* DEBIAN */
 #endif /* EDIT */
Index: pdksh-5.2.14/edit.h
===================================================================
--- pdksh-5.2.14.orig/edit.h	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/edit.h	2009-09-17 00:32:08.000000000 +0200
@@ -55,6 +55,9 @@
 int	x_longest_prefix ARGS((int nwords, char *const *words));
 int	x_basename ARGS((const char *s, const char *se));
 void	x_free_words ARGS((int nwords, char **words));
+#ifdef DEBIAN /* patch from OpenBSD */
+int	x_escape ARGS((const char *, size_t, int (*)(const char *s, size_t len)));
+#endif /* DEBIAN */
 /* emacs.c */
 int 	x_emacs		ARGS((char *buf, size_t len));
 void 	x_init_emacs	ARGS((void));
Index: pdksh-5.2.14/emacs.c
===================================================================
--- pdksh-5.2.14.orig/emacs.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/emacs.c	2009-09-17 00:32:08.000000000 +0200
@@ -138,6 +138,10 @@
 static int	x_e_getc    ARGS((void));
 static void	x_e_putc    ARGS((int c));
 static void	x_e_puts    ARGS((const char *s));
+#ifdef DEBIAN /* patch from OpenBSD */
+static int	x_comment   ARGS((int c));
+static int	x_emacs_putbuf	ARGS((const char *s, size_t len));
+#endif /* DEBIAN */
 static int	x_fold_case ARGS((int c));
 static char	*x_lastcp ARGS((void));
 static void	do_complete ARGS((int flags, Comp_type type));
@@ -269,6 +273,9 @@
 	{ XFUNC_transpose,		0, CTRL('T') },
 #endif
 	{ XFUNC_complete,		1, CTRL('[') },
+#ifdef DEBIAN /* patch from OpenBSD */
+	{ XFUNC_comp_list,		0, CTRL('I') },
+#endif /* DEBIAN */
         { XFUNC_comp_list,		1,	'='  },
 	{ XFUNC_enumerate,		1,	'?'  },
         { XFUNC_expand,			1,	'*'  },
@@ -313,6 +320,9 @@
 	 * entries.
 	 */
         { XFUNC_meta2,			1,	'['  },
+#ifdef DEBIAN  /* patch from OpenBSD */
+        { XFUNC_meta2,			1,	'O'  },
+#endif /* DEBIAN */
 	{ XFUNC_prev_com,		2,	'A'  },
 	{ XFUNC_next_com,		2,	'B'  },
 	{ XFUNC_mv_forw,		2,	'C'  },
@@ -468,6 +478,23 @@
 	return 0;
 }
 
+#ifdef DEBIAN  /* patch from OpenBSD */
+/*
+ * this is used for x_escape() in do_complete()
+ */
+static int
+x_emacs_putbuf(s, len)
+	const char *s;
+	size_t len;
+{
+	int rval;
+
+	if ((rval = x_do_ins(s, len)) != 0)
+		return (rval);
+	return (rval);
+}
+
+#endif /* DEBIAN */
 static int
 x_del_back(c)
 	int c;
@@ -1485,7 +1512,11 @@
 		for (j = 0; j < X_TABSZ; j++)
 			x_tab[i][j] = XFUNC_error;
 	for (i = 0; i < NELEM(x_defbindings); i++)
+#ifndef DEBIAN
 		x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
+#else /* DEBIAN */ /* patch from OpenBSD */
+		x_tab[(unsigned char)x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
+#endif /* DEBIAN */
 			= x_defbindings[i].xdb_func;
 
 	x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
@@ -1754,6 +1785,7 @@
 	int flags;	/* XCF_{COMMAND,FILE,COMMAND_FILE} */
 	Comp_type type;
 {
+#ifndef DEBIAN
 	char **words;
 	int nwords = 0;
 	int start, end;
@@ -1828,8 +1860,13 @@
 			if (nlen > 0) {
 				x_goto(xbuf + start);
 				x_delete(end - start, FALSE);
+#ifndef DEBIAN
 				words[0][nlen] = '\0';
 				x_ins(words[0]);
+#else /* DEBIAN */ /* patch from OpenBSD */
+				x_escape(words[0], nlen, x_emacs_putbuf);
+				x_adjust();
+#endif /* DEBIAN */
 				/* If single match is not a directory, add a
 				 * space to the end...
 				 */
@@ -1841,6 +1878,54 @@
 		}
 		break;
 	}
+#else /* patch from OpenBSD */
+	char **words;
+	int nwords;
+	int start, end, nlen, olen;
+	int is_command;
+	int completed = 0;
+
+	nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
+			    &start, &end, &words, &is_command);
+	/* no match */
+	if (nwords == 0) {
+		x_e_putc(BEL);
+		return;
+	}
+
+	if (type == CT_LIST) {
+		x_print_expansions(nwords, words, is_command);
+		x_redraw(0);
+		x_free_words(nwords, words);
+		return;
+	}
+
+	olen = end - start;
+	nlen = x_longest_prefix(nwords, words);
+	/* complete */
+	if (nlen > olen) {
+		x_goto(xbuf + start);
+		x_delete(olen, FALSE);
+		x_escape(words[0], nlen, x_emacs_putbuf);
+		x_adjust();
+		completed = 1;
+	}
+	/* add space if single non-dir match */
+	if ((nwords == 1) && (!ISDIRSEP(words[0][nlen - 1]))) {
+		x_ins(space);
+		completed = 1;
+	}
+
+	if (type == CT_COMPLIST && !completed) {
+		x_print_expansions(nwords, words, is_command);
+		completed = 1;
+	}
+
+	if (completed)
+		x_redraw(0);
+
+	x_free_words(nwords, words);
+#endif	/* DEBIAN */
 }
 
 /* NAME:
Index: pdksh-5.2.14/io.c
===================================================================
--- pdksh-5.2.14.orig/io.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/io.c	2009-09-17 00:32:08.000000000 +0200
@@ -318,7 +318,7 @@
 		shf_flush(&shf_iob[fd]);
 	if (ofd < 0)		/* original fd closed */
 		close(fd);
-	else {
+	else if (fd != ofd) {
 		ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
 		close(ofd);
 	}
@@ -502,7 +502,9 @@
 	Temp_type type;
 	struct temp **tlist;
 {
+#ifndef DEBIAN
 	static unsigned int inc;
+#endif
 	struct temp *tp;
 	int len;
 	int fd;
@@ -516,6 +518,14 @@
 	tp->name = path = (char *) &tp[1];
 	tp->shf = (struct shf *) 0;
 	tp->type = type;
+#ifdef DEBIAN  /* based on patch from OpenBSD */
+	shf_snprintf(path, len, "%s/kshXXXXXX", dir);
+	fd = mkstemp(path);
+	if (fd >= 0)
+		tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
+	if (fd >= 0)
+		fchmod(fd, 0600);
+#else /* DEBIAN */
 	while (1) {
 		/* Note that temp files need to fit 8.3 DOS limits */
 		shf_snprintf(path, len, "%s/sh%05u.%03x",
@@ -542,6 +552,7 @@
 			break;
 	}
 	tp->next = NULL;
+#endif /* DEBIAN */
 	tp->pid = procpid;
 
 	tp->next = *tlist;
Index: pdksh-5.2.14/vi.c
===================================================================
--- pdksh-5.2.14.orig/vi.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/vi.c	2009-09-17 00:32:08.000000000 +0200
@@ -63,6 +63,9 @@
 static void	vi_pprompt ARGS((int full));
 static void	vi_error ARGS((void));
 static void	vi_macro_reset ARGS((void));
+#ifdef DEBIAN   /* patch from OpenBSD */
+static int	x_vi_putbuf	ARGS((const char *s, size_t len));
+#endif /* DEBIAN */
 
 #define C_	0x1		/* a valid command that isn't a M_, E_, U_ */
 #define M_	0x2		/* movement command (h, l, etc.) */
@@ -235,7 +238,7 @@
 
 	x_putc('\r'); x_putc('\n'); x_flush();
 
-	if (c == -1)
+	if (c == -1 || len <= es->linelen)
 		return -1;
 
 	if (es->cbuf != buf)
@@ -459,15 +462,22 @@
 			else {
 				locpat[srchlen++] = ch;
 				if ((ch & 0x80) && Flag(FVISHOW8)) {
+					if (es->linelen + 2 > es->cbufsize)
+						vi_error();
 					es->cbuf[es->linelen++] = 'M';
 					es->cbuf[es->linelen++] = '-';
 					ch &= 0x7f;
 				}
 				if (ch < ' ' || ch == 0x7f) {
+					if (es->linelen + 2 > es->cbufsize)
+						vi_error();
 					es->cbuf[es->linelen++] = '^';
 					es->cbuf[es->linelen++] = ch ^ '@';
-				} else
+				} else {
+					if (es->linelen >= es->cbufsize)
+						vi_error();
 					es->cbuf[es->linelen++] = ch;
+				}
 				es->cursor = es->linelen;
 				refresh(0);
 			}
@@ -690,7 +700,7 @@
 	/* End nonstandard vi commands } */
 
 	default:
-		if (es->linelen == es->cbufsize - 1)
+		if (es->linelen >= es->cbufsize - 1)
 			return -1;
 		ibuf[inslen++] = ch;
 		if (insert == INSERT) {
@@ -1403,7 +1413,7 @@
 	new = (struct edstate *)alloc(sizeof(struct edstate), APERM);
 	new->cbuf = alloc(old->cbufsize, APERM);
 	new->cbufsize = old->cbufsize;
-	strcpy(new->cbuf, old->cbuf);
+ 	memcpy(new->cbuf, old->cbuf, old->linelen);
 	new->linelen = old->linelen;
 	new->cursor = old->cursor;
 	new->winleft = old->winleft;
@@ -1414,7 +1424,7 @@
 restore_edstate(new, old)
 	struct edstate *old, *new;
 {
-	strncpy(new->cbuf, old->cbuf, old->linelen);
+	memcpy(new->cbuf, old->cbuf, old->linelen);
 	new->linelen = old->linelen;
 	new->cursor = old->cursor;
 	new->winleft = old->winleft;
@@ -1470,6 +1480,19 @@
 	holdlen = 0;
 }
 
+#ifdef DEBIAN /* patch from OpenBSD */
+/*
+ * this is used for calling x_escape() in complete_word()
+ */
+static int
+x_vi_putbuf(s, len)
+	const char *s;
+	size_t len;
+{
+	return putbuf(s, len, 0);
+}
+
+#endif /* DEBIAN */
 static int
 putbuf(buf, len, repl)
 	const char *buf;
@@ -1965,7 +1988,11 @@
 	del_range(start, end);
 	es->cursor = start;
 	for (i = 0; i < nwords; ) {
+#ifndef DEBIAN
 		if (putbuf(words[i], (int) strlen(words[i]), 0) != 0) {
+#else /* DEBIAN */ /* patch from OpenBSD */
+		if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
+#endif /* DEBIAN */
 			rval = -1;
 			break;
 		}
@@ -2068,9 +2095,18 @@
 	buf = save_edstate(es);
 	del_range(start, end);
 	es->cursor = start;
+#ifndef DEBIAN
 	if (putbuf(match, match_len, 0) != 0)
 		rval = -1;
 	else if (is_unique) {
+#else /* DEBIAN */ /* patch from OpenBSD */
+
+	/* escape all shell-sensitive characters and put the result into
+	 * command buffer */
+	rval = x_escape(match, match_len, x_vi_putbuf);
+
+	if (rval == 0 && is_unique) {
+#endif /* DEBIAN */
 		/* If exact match, don't undo.  Allows directory completions
 		 * to be used (ie, complete the next portion of the path).
 		 */
Index: pdksh-5.2.14/c_sh.c
===================================================================
--- pdksh-5.2.14.orig/c_sh.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/c_sh.c	2009-09-17 00:32:08.000000000 +0200
@@ -643,6 +643,7 @@
 		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
 			;
 	}
+#ifndef DEBIAN
 	/* POSIX says set exit status is 0, but old scripts that use
 	 * getopt(1), use the construct: set -- `getopt ab:c "$@"`
 	 * which assumes the exit value set will be that of the ``
@@ -650,6 +651,12 @@
 	 * if there are no command substitutions).
 	 */
 	return Flag(FPOSIX) ? 0 : subst_exstat;
+#else
+	/* On Debian we always want set to return 0 like ksh93 does.
+	 * See: Bug#118476.
+	 */
+	return 0;
+#endif /* DEBIAN */
 }
 
 int
@@ -844,7 +851,7 @@
 			 * keeps them open).
 			 */
 #ifdef KSH
-			if (i > 2 && e->savefd[i])
+			if (!Flag(FSH) &&i > 2 && e->savefd[i])
 				fd_clexec(i);
 #endif /* KSH */
 		}
Index: pdksh-5.2.14/exec.c
===================================================================
--- pdksh-5.2.14.orig/exec.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/exec.c	2009-09-17 00:32:31.000000000 +0200
@@ -228,8 +228,10 @@
 		e->savefd[1] = savefd(1, 0);
 
 		openpipe(pv);
-		ksh_dup2(pv[0], 0, FALSE);
-		close(pv[0]);
+		if (pv[0] != 0) {
+			ksh_dup2(pv[0], 0, FALSE);
+			close(pv[0]);
+		}
 		coproc.write = pv[1];
 		coproc.job = (void *) 0;
 
@@ -448,18 +450,19 @@
 	int volatile flags;
 {
 	int i;
-	int rv = 0;
+	volatile int rv = 0;
 	register char *cp;
 	register char **lastp;
 	static struct op texec; /* Must be static (XXX but why?) */
 	int type_flags;
 	int keepasn_ok;
 	int fcflags = FC_BI|FC_FUNC|FC_PATH;
+	int bourne_function_call = 0;
 
 #ifdef KSH
 	/* snag the last argument for $_ XXX not the same as at&t ksh,
 	 * which only seems to set $_ after a newline (but not in
-	 * functions/dot scripts, but in interactive and scipt) -
+	 * functions/dot scripts, but in interactive and script) -
 	 * perhaps save last arg here and set it in shell()?.
 	 */
 	if (Flag(FTALKING) && *(lastp = ap)) {
@@ -544,9 +547,10 @@
 		newblock();
 		/* ksh functions don't keep assignments, POSIX functions do. */
 		if (keepasn_ok && tp && tp->type == CFUNC
-		    && !(tp->flag & FKSH))
-			type_flags = 0;
-		else
+		    && !(tp->flag & FKSH)) {
+			bourne_function_call = 1;
+ 			type_flags = 0;
+		} else
 			type_flags = LOCAL|LOCAL_COPY|EXPORT;
 	}
 	if (Flag(FEXPORT))
@@ -563,6 +567,8 @@
 				shf_flush(shl_out);
 		}
 		typeset(cp, type_flags, 0, 0, 0);
+		if (bourne_function_call && !(type_flags & EXPORT))
+			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
 	}
 
 	if ((cp = *ap) == NULL) {
@@ -710,10 +716,12 @@
 		}
 
 #ifdef KSH
-		/* set $_ to program's full path */
-		/* setstr() can't fail here */
-		setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,
-		       KSH_RETURN_ERROR);
+		if (!Flag(FSH)) {
+			/* set $_ to program's full path */
+			/* setstr() can't fail here */
+			setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,
+			       KSH_RETURN_ERROR);
+		}
 #endif /* KSH */
 
 		if (flags&XEXEC) {
@@ -1351,6 +1359,8 @@
 				snptreef((char *) 0, 32, "%R", &iotmp), emsg);
 			return -1;
 		}
+		if (u == iop->unit)
+			return 0;		/* "dup from" == "dup to" */
 		break;
 	  }
 	}
@@ -1375,13 +1385,20 @@
 		return -1;
 	}
 	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
-	if (e->savefd[iop->unit] == 0)
-		/* c_exec() assumes e->savefd[fd] set for any redirections.
-		 * Ask savefd() not to close iop->unit - allows error messages
-		 * to be seen if iop->unit is 2; also means we can't lose
-		 * the fd (eg, both dup2 below and dup2 in restfd() failing).
-		 */
-		e->savefd[iop->unit] = savefd(iop->unit, 1);
+	if (e->savefd[iop->unit] == 0) {
+#ifdef DEBIAN /* patch from OpenBSD */
+		/* If these are the same, it means unit was previously closed */
+		if (u == iop->unit)
+			e->savefd[iop->unit] = -1;
+		else
+#endif
+			/* c_exec() assumes e->savefd[fd] set for any redirections.
+			* Ask savefd() not to close iop->unit - allows error messages
+			* to be seen if iop->unit is 2; also means we can't lose
+			* the fd (eg, both dup2 below and dup2 in restfd() failing).
+			*/
+			e->savefd[iop->unit] = savefd(iop->unit, 1);
+	}
 
 	if (do_close)
 		close(iop->unit);
Index: pdksh-5.2.14/history.c
===================================================================
--- pdksh-5.2.14.orig/history.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/history.c	2009-09-17 00:32:08.000000000 +0200
@@ -858,8 +858,8 @@
 		/*
 		 * check on its validity
 		 */
-		if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {
-			if ((int)base !=  -1)
+		if (base == MAP_FAILED || *base != HMAGIC1 || base[1] != HMAGIC2) {
+			if (base !=  MAP_FAILED)
 				munmap((caddr_t)base, hsize);
 			hist_finish();
 			unlink(hname);
@@ -893,7 +893,7 @@
 static int
 hist_count_lines(base, bytes)
 	register unsigned char *base;
-	register int bytes;
+	int bytes;
 {
 	State state = shdr;
 	register lines = 0;
@@ -1015,8 +1015,8 @@
 	register int bytes;
 {
 	State state;
-	int	lno;
-	unsigned char	*line;
+	int	lno = -1;
+	unsigned char	*line = NULL;
 
 	for (state = shdr; bytes-- > 0; base++) {
 		switch (state) {
@@ -1105,7 +1105,7 @@
 			/* someone has added some lines */
 			bytes = sizenow - hsize;
 			base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);
-			if ((int)base == -1)
+			if (base == MAP_FAILED)
 				goto bad;
 			new = base + hsize;
 			if (*new != COMMAND) {
Index: pdksh-5.2.14/jobs.c
===================================================================
--- pdksh-5.2.14.orig/jobs.c	2009-09-17 00:32:06.000000000 +0200
+++ pdksh-5.2.14/jobs.c	2009-09-17 00:32:08.000000000 +0200
@@ -627,8 +627,10 @@
 				SS_RESTORE_IGN|SS_FORCE);
 			if (!(flags & (XPIPEI | XCOPROC))) {
 				int fd = open("/dev/null", 0);
-				(void) ksh_dup2(fd, 0, TRUE);
-				close(fd);
+				if (fd != 0) {
+					(void) ksh_dup2(fd, 0, TRUE);
+					close(fd);
+				}
 			}
 		}
 		remove_job(j, "child");	/* in case of `jobs` command */
@@ -811,7 +813,7 @@
 	int	sig;
 {
 	Job	*j;
-	Proc	*p;
+/*	Proc	*p; */ /* unused */
 	int	rv = 0;
 	int	ecode;
 #ifdef JOB_SIGS
Index: pdksh-5.2.14/lex.c
===================================================================
--- pdksh-5.2.14.orig/lex.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/lex.c	2009-09-17 00:32:08.000000000 +0200
@@ -699,11 +699,13 @@
 
 		  case '(':  /*)*/
 #ifdef KSH
-			if ((c2 = getsc()) == '(') /*)*/
-				/* XXX need to handle ((...); (...)) */
-				c = MDPAREN;
-			else
-				ungetsc(c2);
+			if (!Flag(FSH)) {
+				if ((c2 = getsc()) == '(') /*)*/
+					/* XXX need to handle ((...); (...)) */
+					c = MDPAREN;
+				else
+					ungetsc(c2);
+			}
 #endif /* KSH */
 			return c;
 		  /*(*/
@@ -1119,7 +1121,7 @@
 		 */
 		{
 			struct shf *shf;
-			char *ps1;
+			char * volatile ps1;
 			Area *saved_atemp;
 
 			ps1 = str_val(global("PS1"));
Index: pdksh-5.2.14/main.c
===================================================================
--- pdksh-5.2.14.orig/main.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/main.c	2009-09-17 00:32:08.000000000 +0200
@@ -201,7 +201,24 @@
 	change_flag(FPOSIX, OF_SPECIAL, 1);
 #endif /* POSIXLY_CORRECT */
 
-	/* import enviroment */
+#ifdef DEBIAN /* patch from OpenBSD */
+	/* Check to see if we're /bin/sh. */
+	if (!strcmp(&kshname[strlen(kshname) - 3], "/sh")
+	    || !strcmp(kshname, "sh") || !strcmp(kshname, "-sh"))
+		Flag(FSH) = 1;
+
+	/* Set edit mode to emacs by default, may be overridden
+	* by the environment or the user.  Also, we want tab completion
+	* on in vi by default. */
+#if defined(EDIT) && defined(EMACS)
+	change_flag(FEMACS, OF_SPECIAL, 1);
+#endif /* EDIT && EMACS */
+	#if defined(EDIT) && defined(VI)
+	Flag(FVITABCOMPLETE) = 1;
+#endif /* EDIT && VI */
+#endif /* DEBIAN */
+
+	/* import environment */
 	if (environ != NULL)
 		for (wp = environ; *wp != NULL; wp++)
 			typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
Index: pdksh-5.2.14/misc.c
===================================================================
--- pdksh-5.2.14.orig/misc.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/misc.c	2009-09-17 00:32:08.000000000 +0200
@@ -159,6 +159,7 @@
 	{ "posix",	  0,		OF_ANY }, /* non-standard */
 	{ "privileged",	'p',		OF_ANY },
 	{ "restricted",	'r',	    OF_CMDLINE },
+	{ "sh",		  0,		OF_ANY }, /* non-standard */ /* from OpenBSD */
 	{ "stdin",	's',	    OF_CMDLINE }, /* pseudo non-standard */
 	{ "trackall",	'h',		OF_ANY },
 	{ "verbose",	'v',		OF_ANY },
@@ -309,8 +310,15 @@
 #ifdef OS2
 		;
 #else /* OS2 */
+#ifndef DEBIAN
 		setuid(ksheuid = getuid());
 		setgid(getgid());
+#else /* patch from OpenBSD */
+		seteuid(ksheuid = getuid());
+		setuid(ksheuid);
+		setegid(getgid());
+		setgid(getgid());
+#endif /* DEBIAN */
 #endif /* OS2 */
 	} else if (f == FPOSIX && newval) {
 #ifdef BRACE_EXPAND
@@ -471,6 +479,7 @@
 	const char *as;
 	int *ai;
 {
+#ifndef DEBIAN
 	const char *s;
 	register int n;
 	int sawdigit = 0;
@@ -484,6 +493,19 @@
 	if (*s || !sawdigit)
 		return 0;
 	return 1;
+#else /* patch from OpenBSD */
+	char *p;
+	long n;
+
+	n = strtol(as, &p, 10);
+
+	if (!*as || *p || INT_MIN >= n || n >= INT_MAX)
+		return 0;
+
+	*ai = (int)n;
+	return 1;
+#endif
+
 }
 
 /* getn() that prints error */
Index: pdksh-5.2.14/sh.h
===================================================================
--- pdksh-5.2.14.orig/sh.h	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/sh.h	2009-09-17 00:32:08.000000000 +0200
@@ -382,7 +382,11 @@
  */
 
 typedef struct Area {
+#ifndef DEBIAN
 	struct Block *freelist;	/* free list */
+#else /* patch from OpenBSD */
+	struct link *freelist;  /* free list */
+#endif
 } Area;
 
 EXTERN	Area	aperm;		/* permanent object space */
@@ -501,6 +505,7 @@
 	FPOSIX,		/* -o posix: be posixly correct */
 	FPRIVILEGED,	/* -p: use suid_profile */
 	FRESTRICTED,	/* -r: restricted shell */
+	FSH,		/* -o sh: favor sh behavour */
 	FSTDIN,		/* -s: (invocation) parse stdin */
 	FTRACKALL,	/* -h: create tracked aliases for all commands */
 	FVERBOSE,	/* -v: echo input */
Index: pdksh-5.2.14/tests/th
===================================================================
--- pdksh-5.2.14.orig/tests/th	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/tests/th	2009-09-17 00:32:08.000000000 +0200
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
 
 #
 # Test harness for pdksh tests.
@@ -131,7 +131,7 @@
 $os = defined $^O ? $^O : 'unknown';
 
 require 'signal.ph' unless $os eq 'os2';
-require 'errno.ph' unless $os eq 'os2';
+# require 'errno.ph' unless $os eq 'os2';
 require 'getopts.pl';
 
 ($prog = $0) =~ s#.*/##;
Index: pdksh-5.2.14/trap.c
===================================================================
--- pdksh-5.2.14.orig/trap.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/trap.c	2009-09-17 00:32:08.000000000 +0200
@@ -68,6 +68,8 @@
 alarm_catcher(sig)
 	int sig;
 {
+	int errno_ = errno;
+
 	if (ksh_tmout_state == TMOUT_READING) {
 		int left = alarm(0);
 
@@ -77,6 +79,7 @@
 		} else
 			alarm(left);
 	}
+	errno = errno_;
 	return RETSIGVAL;
 }
 #endif /* KSH */
@@ -111,6 +114,7 @@
 	int i;
 {
 	Trap *p = &sigtraps[i];
+	int errno_ = errno;
 
 	trap = p->set = 1;
 	if (p->flags & TF_DFL_INTR)
@@ -125,6 +129,7 @@
 	if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
 		sigaction(i, &Sigact_trap, (struct sigaction *) 0);
 #endif /* V7_SIGNALS */
+	errno = errno_;
 	return RETSIGVAL;
 }
 
Index: pdksh-5.2.14/tree.c
===================================================================
--- pdksh-5.2.14.orig/tree.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/tree.c	2009-09-17 00:32:08.000000000 +0200
@@ -506,7 +506,7 @@
 		for (tw = t->vars; *tw++ != NULL; )
 			;
 		rw = r->vars = (char **)
-			alloc((int)(tw - t->vars) * sizeof(*tw), ap);
+			alloc((tw - t->vars + 1) * sizeof(*tw), ap);
 		for (tw = t->vars; *tw != NULL; )
 			*rw++ = wdcopy(*tw++, ap);
 		*rw = NULL;
@@ -518,7 +518,7 @@
 		for (tw = t->args; *tw++ != NULL; )
 			;
 		rw = r->args = (char **)
-			alloc((int)(tw - t->args) * sizeof(*tw), ap);
+			alloc((tw - t->args + 1) * sizeof(*tw), ap);
 		for (tw = t->args; *tw != NULL; )
 			*rw++ = wdcopy(*tw++, ap);
 		*rw = NULL;
@@ -679,7 +679,7 @@
 
 	for (ior = iow; *ior++ != NULL; )
 		;
-	ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);
+	ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
 
 	for (i = 0; iow[i] != NULL; i++) {
 		register struct ioword *p, *q;
Index: pdksh-5.2.14/c_test.c
===================================================================
--- pdksh-5.2.14.orig/c_test.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/c_test.c	2009-09-17 00:32:08.000000000 +0200
@@ -124,10 +124,10 @@
 	te.pos.wp = wp + 1;
 	te.wp_end = wp + argc;
 
-	/* 
+	/*
 	 * Handle the special cases from POSIX.2, section 4.62.4.
-	 * Implementation of all the rules isn't necessary since 
-	 * our parser does the right thing for the ommited steps.
+	 * Implementation of all the rules isn't necessary since
+	 * our parser does the right thing for the omitted steps.
 	 */
 	if (argc <= 5) {
 		char **owp = wp;
@@ -238,7 +238,7 @@
 			if (not)
 				res = !res;
 		}
-		return res; 
+		return res;
 	  case TO_FILRD: /* -r */
 		return test_eaccess(opnd1, R_OK) == 0;
 	  case TO_FILWR: /* -w */
@@ -456,10 +456,12 @@
 	}
 #endif /* !HAVE_DEV_FD */
 
-	/* On most (all?) unixes, access() says everything is executable for
+	res = eaccess(path, mode);
+	/*
+	 * On most (all?) unixes, access() says everything is executable for
 	 * root - avoid this on files by using stat().
 	 */
-	if ((mode & X_OK) && ksheuid == 0) {
+	if (res == 0 && ksheuid == 0 && (mode & X_OK)) {
 		struct stat statb;
 
 		if (stat(path, &statb) < 0)
@@ -469,13 +471,7 @@
 		else
 			res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
 				? 0 : -1;
-		/* Need to check other permissions?  If so, use access() as
-		 * this will deal with root on NFS.
-		 */
-		if (res == 0 && (mode & (R_OK|W_OK)))
-			res = eaccess(path, mode);
-	} else
-		res = eaccess(path, mode);
+	}
 
 	return res;
 }
Index: pdksh-5.2.14/eval.c
===================================================================
--- pdksh-5.2.14.orig/eval.c	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/eval.c	2009-09-17 00:32:08.000000000 +0200
@@ -870,8 +870,11 @@
 		openpipe(pv);
 		shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
 		ofd1 = savefd(1, 0);	/* fd 1 may be closed... */
-		ksh_dup2(pv[1], 1, FALSE);
-		close(pv[1]);
+		if (pv[1] != 1) {
+			ksh_dup2(pv[1], 1, FALSE);
+			close(pv[1]);
+		}
+
 		execute(t, XFORK|XXCOM|XPIPEO);
 		restfd(1, ofd1);
 		startlast();
Index: pdksh-5.2.14/tests/regress.t
===================================================================
--- pdksh-5.2.14.orig/tests/regress.t	2009-09-17 00:31:58.000000000 +0200
+++ pdksh-5.2.14/tests/regress.t	2009-09-17 00:32:08.000000000 +0200
@@ -156,11 +156,12 @@
 		echo $?
 	shoud not print 0. (according to /bin/sh, at&t ksh88, and the
 	getopt(1) man page - not according to POSIX)
+	For Debian - it should print 0, cf. bug#118476.
 stdin:
 	set -- `false`
 	echo $?
 expected-stdout:
-	1
+	0
 ---
 
 
